Seattle’s downtown skyline. Credit: Adam Romanowicz
Seattle is the largest city in Washington State. Situated between the Puget Sound and Lake Washington, it is a largely urban area that is home to nearly 730,000 people. Known for its mild weather and persistent rain, Seattle’s climate is temperate, which until recently has meant that it has avoided extreme temperature events, has abundant fresh water, and is famous for its lush green foliage. However, June of 2021 saw many of the hottest days in Seattle’s history. Moreover, wildfires have become increasingly common in over the past decade. Together, these troubling trends raise questions about how Seattle’s climate is changing and what adaptation measures should be implemented to adapt to these changes. The following report analyzes climate trends in Seattle using daily climate data from the National Climatic Data Center (NCDC). First, average climate variables relating to temperature and precipitation are explored to discover how Seattle’s climate has changed from 1949 until today. Then, frequency and severity of climate extremes are examined.
Wildfire smoke blankets the city. Credit: Komo 4 News
knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE)
library(here)
library(tidyverse)
library(janitor)
library(lubridate)
library(tsibble)
library(feasts)
library(gghighlight)
library(plotly)
library(Kendall)
library(kableExtra)
library(broom)
Citation: Climate Data Online (CDO). “National Climatic Data Center (NCDC).” Accessed April 8, 2022. https://www.ncdc.noaa.gov/cdo-web/datasets#GHCND.
seattle <- read_csv(here("data", "seattle.csv")) %>%
clean_names() %>%
select(-station, -name, -starts_with("wt")) %>%
mutate(month = month(date, label = TRUE)) %>%
mutate(year = year(date)) %>%
drop_na(tmax, tmin, prcp)
# data wrangling
# converting the dataframe to a time series
seattle_ts <- seattle %>%
as_tsibble(key = NULL, index = date)
# monthly summary statistics
seattle_monthly <- seattle_ts %>%
index_by(year_month = ~yearmonth(.)) %>%
summarize(mean_daily_max_temp = mean(tmax, na.rm = TRUE),
mean_daily_min_temp = mean(tmin, na.rm = TRUE),
mean_daily_precip = mean(prcp, na.rm = TRUE),
max_temp_monthly = max(tmax, na.rm = TRUE),
min_temp_monthly = min(tmin, na.rm = TRUE),
monthly_precip = sum(prcp, na.rm = TRUE)) %>%
mutate(year = year(year_month))
# yearly summary statistics
seattle_yearly <- seattle_ts %>%
index_by(year) %>%
summarize(mean_daily_max_temp = mean(tmax, na.rm = TRUE),
mean_daily_min_temp = mean(tmin, na.rm = TRUE),
mean_daily_precip = mean(prcp, na.rm = TRUE),
total_yearly_precip = sum(prcp)) %>%
filter(year != "2022") %>%
filter(year != "1948")
# hottest 10 years on record
seattle_hottest <- seattle_yearly %>%
slice_max(n = 10, order_by = mean_daily_max_temp)
# smooth yearly ggplot
ggplot(data = seattle_yearly) +
geom_smooth(method = "lm",
color = "gray25",
aes(x = year,
y = mean_daily_max_temp)) +
geom_smooth(method = "lm",
color = "gray25",
aes(x = year,
y = mean_daily_min_temp)) +
geom_point(aes(x = year,
y = mean_daily_max_temp,
color = mean_daily_max_temp),
size = 2) +
geom_point(aes(x = year,
y = mean_daily_min_temp,
color = mean_daily_min_temp),
size = 2) +
scale_color_gradientn(colors = c("deepskyblue4", "firebrick")) +
theme_minimal(14) +
theme(legend.position = "none") +
labs(x = element_blank(),
y = "Average Daily Temperature (F)") +
geom_text(x = 2010, y = 57, label = "Daily Max", color = "firebrick", size = 7) +
geom_text(x = 2010, y = 43, label = "Daily Min", color = "deepskyblue4", size = 7)
Figure 1 shows Seattle’s average daily maximum temperature (red) and average daily minimum temperature (blue) by year. Trendline was fitted using simple linear regression. Grey shading represents the bounds of a 95% confidence interval.
# seasonplot
seattle_monthly %>%
gg_season(y = mean_daily_max_temp) +
gghighlight(year %in% c("2021", "2020")) +
theme_minimal(14) +
labs(x = "Month",
y = "Average Daily Temperature (F)")
<<<<<<< HEAD
Figure 2 shows seasonal variation in daily maximum temperature across from 1949-2021. Each grey line represents a year since 1949. The past two years are highlighted for reference.
ggplot(data = seattle_yearly, aes(x = year, y = total_yearly_precip)) +
geom_smooth(method = "lm", color = "deepskyblue4") +
geom_point() +
theme_minimal(14) +
labs(x = element_blank(), y = "Total Annual Precipitation (inches)")
Figure 3 shows Seattle’s annual precipitation (inches) since 1949. Trendline was fitted using simple linear regression. Grey shading represents the bounds of a 95% confidence interval.
seattle_monthly %>%
gg_season(y = monthly_precip) +
gghighlight(year %in% c("2021", "2020")) +
theme_minimal(14) +
labs(x = element_blank(), y = "Monthly Precipitation (inches)")
<<<<<<< HEAD
Figure 4 shows seasonal variation in monthly precipitation totals. Each grey line represents a year from 1949-2021. The past two years are highlighted for reference.
Table 1 displays the results of statistical testing performed on the climate trends data. Slope and P value refer to the results of simple linear regression. M-K significance level refers to the results of Mann-Kendall test performed on each measure.
# linear regressions
# max temp
temp_max_lm <- lm(mean_daily_max_temp ~ year, data = seattle_yearly)
temp_max_tidy <- tidy(temp_max_lm)
# min temp
temp_min_lm <- lm(mean_daily_min_temp ~ year, data = seattle_yearly)
temp_min_tidy <- tidy(temp_min_lm)
# annual precip
yearly_precip_lm <- lm(total_yearly_precip ~ year, data = seattle_yearly)
yearly_precip_tidy <- tidy(yearly_precip_lm)
# monthly precip
monthly_precip_lm <- lm(monthly_precip ~ year, data = seattle_monthly)
monthly_precip_tidy <- tidy(monthly_precip_lm)
lm_tidy_all <- rbind(temp_max_tidy,
temp_min_tidy,
yearly_precip_tidy,
monthly_precip_tidy)
lm_tidy_all_coef <- lm_tidy_all %>%
filter(term == "year") %>%
select(-statistic, -std.error, -term)
names_vector <- c("Average Maximum Daily Temperature (F)", "Average Minimum Daily Temperature (F)", "Annual Precipitation (inches)", "Monthly Precipitation (inches)")
lm_tidy_all_clean <- data.frame(names_vector, lm_tidy_all_coef)
# Mann Kendall testing for significance
mk1 <- MannKendall(seattle_yearly$mean_daily_max_temp)
mkt1 <- mk1$sl
mk2 <- MannKendall(seattle_yearly$mean_daily_min_temp)
mkt2 <- mk2$sl
mk3 <- MannKendall(seattle_yearly$total_yearly_precip)
mkt3 <- mk3$sl
mk4 <- MannKendall(seattle_monthly$monthly_precip)
mkt4 <- mk4$sl
mk_vector <- c(mkt1, mkt2, mkt3, mkt4)
stats_table <- data.frame(lm_tidy_all_clean, mk_vector)
kable(stats_table,
col.names = c("Measurement", "Slope", "P value", "M-K Significance Level"),
digits = c(0, 4, 4, 4)) %>%
kable_minimal(full_width = FALSE)
| Measurement | Slope | P value | M-K Significance Level |
|---|---|---|---|
| Average Maximum Daily Temperature (F) | 0.0409 | 0.0000 | 0.0000 |
| Average Minimum Daily Temperature (F) | 0.0533 | 0.0000 | 0.0000 |
| Annual Precipitation (inches) | 0.0071 | 0.8471 | 0.8977 |
| Monthly Precipitation (inches) | 0.0005 | 0.9087 | 0.9896 |
\[\\[.5in]\]
# Data wrangling
# Temperature
# hottest day of the year 1949-2021
seattle_hottest_days <- seattle_ts %>%
index_by(year) %>%
summarize(hottest_day = max(tmax)) %>%
filter(year != "2022") %>%
filter(year != "1948")
# days above 85 and days below freezing 1949-2021
seattle_hot_days <- seattle_ts %>%
index_by(year) %>%
summarize(days_above_85 = sum(ifelse(tmax >= 90, 1, 0))) %>%
filter(year != "2022") %>%
filter(year != "1948")
# days below freezing 1949-2021
seattle_below_freezing <- seattle_ts %>%
index_by(year) %>%
summarize(days_below_freezing = sum(ifelse(tmin <= 32, 1, 0))) %>%
filter(year != "2022") %>%
filter(year != "1948")
# Data wrangling
# precipitation extremes
# days with over an inch of precipitation
seattle_wet_days <- seattle_ts %>%
index_by(year) %>%
summarize(wet_days = sum(ifelse(prcp >= 1, 1, 0))) %>%
filter(year != "2022") %>%
filter(year != "1948")
# days with no precipitation
seattle_dry_days <- seattle_ts %>%
index_by(year) %>%
summarize(dry_days = sum(ifelse(prcp < 0.1, 1, 0))) %>%
filter(year != "2022") %>%
filter(year != "1948")
# plotting hottest day of the year 1949-2021
ggplot(data = seattle_hottest_days) +
geom_smooth(method = "lm",
color = "gray25",
aes(x = year,
y = hottest_day)) +
geom_point(aes(x = year,
y = hottest_day,
color = hottest_day),
size = 2) +
scale_color_gradientn(colors = c("firebrick")) +
theme_minimal(14) +
theme(legend.position = "none") +
labs(x = element_blank(),
y = "Hottest Day of the Year (F)")
# plotting number of days over 85
ggplot(data = seattle_hot_days) +
geom_smooth(method = "lm",
color = "gray25",
aes(x = year,
y = days_above_85)) +
geom_point(aes(x = year,
y = days_above_85,
color = days_above_85),
size = 2) +
scale_color_gradientn(colors = c("firebrick")) +
theme_minimal(14) +
theme(legend.position = "none") +
labs(x = element_blank(),
y = "Number of Days Over 85 Degrees (F)")
<<<<<<< HEAD
Figure 5 displays the number of days per year in Seattle where the daily maximum temperature exceeded 85 degrees Fahrenehit. The trendline was fitted using simple linear regression. Grey shading represents the bounds of a 95% confidence interval.
# plotting number of days below freezing
ggplot(data = seattle_below_freezing) +
geom_smooth(method = "lm",
color = "gray25",
aes(x = year,
y = days_below_freezing)) +
geom_point(aes(x = year,
y = days_below_freezing,
color = days_below_freezing),
size = 2) +
scale_color_gradientn(colors = c("deepskyblue4")) +
theme_minimal(14) +
theme(legend.position = "none") +
labs(x = element_blank(),
y = "Number of Nights Below Freezing")
<<<<<<< HEAD
<<<<<<< HEAD Figure 6 shows the number of days per year in Seattle where the minimum daily temperature dropped below freezing. The trendline was fitted using simple linear regression. Grey shading represents the bounds of a 95% confidence interval. ======= >>>>>>> 926dd6cb0f7846f2b5689e810f06b56de0d95963
ggplot(data = seattle_wet_days) +
geom_smooth(method = "lm",
color = "gray25",
aes(x = year,
y = wet_days)) +
geom_point(aes(x = year,
y = wet_days,
color = wet_days),
size = 2) +
theme_minimal(14) +
theme(legend.position = "none") +
labs(x = element_blank(),
y = "Number of Days with over 1 Inch of Precipitation")
<<<<<<< HEAD
Figure 7 shows the number of wet days in Seattle per year, determined by days with at least 1 inch of precipitation. The trendline was fitted using simple linear regression. Grey shading represents the bounds of a 95% confidence interval.
ggplot(data = seattle_dry_days) +
geom_smooth(method = "lm",
color = "gray25",
aes(x = year,
y = dry_days)) +
geom_point(aes(x = year,
y = dry_days,
color = dry_days),
size = 2) +
theme_minimal(14) +
theme(legend.position = "none") +
labs(x = element_blank(),
y = "Number of Days with No Precipitation")
<<<<<<< HEAD
Refer to your answer for part 1 when choosing your metrics; why are these metrics likely to be relevant, given the climate change impacts you expect at this location?
======= <<<<<<< HEAD Figure 8 shows the number of dry days in Seattle per year, respresented by days where there was no measured precipitation. The trendline was fitted using simple linear regression. Grey shading represents the bounds of a 95% confidence interval.
Refer to your answer for part 1 when choosing your metrics; why are these metrics likely to be relevant, given the climate change impacts you expect at this location? =======
Refer to your answer for part 1 when choosing your metrics; why are these metrics likely to be relevant, given the climate change impacts you expect at this location? >>>>>>> 926dd6cb0f7846f2b5689e810f06b56de0d95963
>>>>>>> dd256ab879007ea8d2d67b5d71e1edfb8ca1490f